﻿#pragma once

#include <type_traits>
#include <array>
#include "desCommonType.hpp"
#include "desCommonTools.hpp"


namespace des {

namespace key {

struct KeyGenRule {

	using PC1Table = std::array<int8, 56>;
	using PC2Table = std::array<int8, 48>;
	using LeftShiftDigit = std::array<int8, 16>;
};



template <typename _rule>
concept KeyGenerateConcept = requires {
	requires std::is_base_of_v<KeyGenRule, _rule>;
	requires std::is_same_v<std::decay_t<decltype(_rule::pc1table)>, typename _rule::PC1Table>;
	requires std::is_same_v<std::decay_t<decltype(_rule::pc2table)>, typename _rule::PC2Table>;
	requires std::is_same_v<std::decay_t<decltype(_rule::leftShiftDigit)>, typename _rule::LeftShiftDigit>;
};



// 置换1
template <typename _rule>
inline constexpr
int64 __keyPC_1(int64 const src) {

	return __bitPermutation(src, _rule::pc1table);
}



// 置换2
template <typename _rule>
inline constexpr
int64 __keyPC_2(int64 const src) {

	return __bitPermutation(src, _rule::pc2table);
}



// 通过56位原秘钥生成16轮48位秘钥
template <KeyGenerateConcept _rule>
inline constexpr
std::array<int64, 16> keyGenerate(int64 const src) {

	std::array<int64, 16> subKeys = {};

	int64 pc1key = __keyPC_1<_rule>(src);
	for (int8 i = 0; i != 16; ++i) {

		int64 constexpr scalar = 0x8000000800000000;
		// 8000000	left 28 bits
		// 8000000	right 28 bits
		// 00		8 bits
		int64 andOperModel = 0;
		for (int8 j = 0; j != _rule::leftShiftDigit[i]; ++j) {
			andOperModel |= (scalar >> j);
		}

		// 获取左移后将被覆盖掉的位
		int64 recordCover = andOperModel & pc1key;
		// 左移
		pc1key <<= _rule::leftShiftDigit[i];
		// 将记录下的被覆盖掉的位添加至末尾
		pc1key &= (~(andOperModel >> (28 - _rule::leftShiftDigit[i])));	// 清除多余位
		pc1key |= (recordCover >> (28 - _rule::leftShiftDigit[i]));		// 放置被覆盖掉的位

		int64 pc2key = __keyPC_2<_rule>(pc1key);

		subKeys[i] = pc2key;
	}

	return subKeys;
}



}
}
